home *** CD-ROM | disk | FTP | other *** search
- ; ***************************************************************************
- ; * *
- ; * Hitachi CDR-3600/1600S C D - R O M Device Driver *
- ; * Copyright reserved by Hitachi, Ltd. *
- ; * *
- ; * C D - R O M Device Driver Hardware Dependent Interface. *
- ; * *
- ; * This file defines the hardware dependent interface to the valid CD-ROM *
- ; * device driver commands, and helper functions in the file MSCDEX.ASM. *
- ; * The implementation of a CD-ROM device driver entails replacing these *
- ; * fucntions with suitable equivalents which adhere to the entry and exit *
- ; * conditions defined. *
- ; * *
- ; * History: *
- ; * *
- ; * Created (v1.02) *
- ; * Oct. 07,1985 -by- H. ONO *
- ; * Modified (v2.10) *
- ; * 1989-8-03 -by- T.ENOKI *
- ; * Modified (v2.20) *
- ; * Fri Jun 22 1990 -by- Michael Edwards *
- ; * *
- ; * Extensive code clean-up, seperated device dependent *
- ; * code into this module, device independent into CD.ASM *
- ; * *
- ; * Fixed bug in STOP AUDIO where wasn't re-setting the *
- ; * paused bit correctly, and where was always returning *
- ; * through busy_good which says the drive is busy with *
- ; * an audio play request. *
- ; * *
- ; * Changed AUDIO command to return busy bit set if successful, *
- ; * and fixed bu in conversion of the passed starting sector *
- ; * number to redbook format. *
- ; * *
- ; * Changed IOCTL OUTPUT's audio_channel_ctrl subfunction *
- ; * to detect assigning both input channels to one output *
- ; * channel, and suppressing the other. *
- ; * *
- ; * Changed IOCTL INPUT's get UPC code to return sector not found error *
- ; * (in addition to zero CONTROL/ADR and UPC bytes) when the UPC code is*
- ; * not present on the disc. *
- ; * *
- ; * Moved initializing timing variables from CDREAD to cdrom_init(). *
- ; * Changed timing checks done after initialization to use the system's *
- ; * 18Hz clock long interger value (at 004:006c) instead of installing *
- ; * the timer interrupt routine. *
- ; * *
- ; * Modified (v2.20) -by- JohnYG 8/22/90 *
- ; * v2.2b *
- ; * Rewrote IOCTL Input cdrom_upc_code similar to Qchannel Info. *
- ; * Rewrote IOCTL Input cdrom_volume_size to use information from *
- ; * cdrom_audio_diskinfo rather than the undocumented call to hardware *
- ; * through CDREAD UCOM. *
- ; * v2.2c *
- ; * Changed timeout values. Fixed VolumeSize bug introduced in v2.2b *
- ; * v2.2d *
- ; * Force the power save during play. The default is not being set *
- ; * for the AMDEK, for some reason. *
- ; * *
- ; * Modified (v2.20) -by- JohnYG 10/1/90 *
- ; * Final Release 10/1/90 *
- ; * *
- ; ***************************************************************************
-
-
- CNT3 equ 8000 ;scan TOC timeout for read Q-channel
- RETRY_COUNT equ 5
- SCAN_COUNT equ 150
- UPC_COUNT equ 150*2*RETRY_COUNT
-
- include cd.inc
- include mscdex.inc
- include macros.mac
-
- public cdrom_read
- public cdrom_prefetch
- public cdrom_seek
- public cdrom_play_audio
- public cdrom_stop_audio
- public cdrom_location_head
- public cdrom_audio_channel_info
- public cdrom_read_drive_bytes
- public cdrom_device_status
- public cdrom_volume_size
- public cdrom_media_changed
- public cdrom_audio_diskinfo
- public cdrom_audio_trackinfo
- public cdrom_audio_Qchannel
- public cdrom_audio_Subchannel
- public cdrom_upc_code
- public cdrom_audio_status_info
- public cdrom_eject
- public cdrom_lock_door
- public cdrom_reset_drive
- public cdrom_audio_channel_ctrl
- public cdrom_write_drive_ctrl
- public cdrom_close_tray
- public cdrom_input_flush
- public cdrom_device_open
- public cdrom_device_close
- public cdrom_current_loc
- public cdrom_drive_status
- public cdrom_audio_check
- public cdrom_init
-
- extrn BUF : BYTE
- extrn CPU_MODE : BYTE
- extrn CLOCK_MODE : BYTE
- extrn CURRENT_IF_MODE : BYTE
- extrn STA_CODE : BYTE
- extrn TWICE : BYTE
- extrn IF_FLAG : BYTE
- extrn CLOCK_COUNT : BYTE
- extrn ERRCNT : BYTE
- extrn CURRENT_IF : WORD
-
- extrn INSB_LOOP : FAR
- extrn CDREAD : FAR
- extrn _INSB_LOOP_ENT : FAR
- extrn _STATUS_COMMAND : FAR
-
- extrn bcd2red : near
- extrn red2hsg : near
- extrn hsg2red : near
- extrn bcd2bin : near
- extrn very_end : near
-
- extrn DeviceHeader : word
- extrn units : byte
-
- _TEXT segment byte public 'CODE'
- assume cs:_TEXT
-
-
- disc_changed db 8 dup(0)
- play_para db 6 dup(0) ;start/end play play time for device
- audio_vol db 0 ;channel switching for drive 0
- db 0 ;volume for drive 1
- db 0 ; " 2
- db 0 ; " 3
- db 0 ; " 4
- db 0 ; " 5
- db 0 ; " 6
- db 0 ; " 7
-
- audio_ch_work label byte
- left_ich db 0 ;input ch. for output ch.0(left)
- left_vol db 0ffh ;volume for ch. 0(00h or other)
- right_ich db 1 ;input ch. for output ch.1(right)
- right_vol db 0ffh ;volume for ch 1
- left2_ich db 2 ;input ch. for output ch.2(left)
- left2_vol db 0 ;volume for ch 2
- right2_ich db 3 ;input ch. for output ch.3(right)
- right2_vol db 0 ;volume for ch 3
- audio_ch_work_size = $-audio_ch_work
-
- scans dw 0 ;retry scanning
- i1 db ? ;retry counter for audio_diskinfo
- i2 dw ? ;"
- last_point db ? ;last Q-channel point
- ok db ? ;flag for audio_diskinfo
- vol_cnt label word ; " " " for vol-size
- loc_cnt dw 0 ; " " " for loc of head
- pwr_save db 9 ; 0 - release other - set power save
-
- qbuf db size _QchanInfo dup(0) ;subcode-Q work
- toc_drive db 0ffh ;which drive toc_table is for
- toc_table label byte
- db size _QchanInfo dup(0) ;POINT=A0,1st TNO
- db size _QchanInfo dup(0) ;POINT=A1,last TNO
- db size _QchanInfo dup(0) ;POINT=A2,lead-out
- db 99 dup (size _QchanInfo dup(0)) ;POINT=A0,1st TNO
- a_flag db ? ;0/1 = audio_disk/trackinfo
- app_xfer_buffer dd 0 ;temp save for app's xfer buffer
-
- ;============================================================
- ;
- ; READ LONG command
- ;
- ; Issue a read command to the drive.
- ;
- ; Entry:
- ; dl:ax - redbook address for read
- ; cx - number of sectors to read
- ; es:bx - transfer address for data
- ; dh - drive number (0 based)
- ; di - read mode (0 = cooked, 1 = raw)
- ;
- ; Exit:
- ; carry set - error occurred, ax contains status word
- ; carry clear - read was successful
- ; trashes si
- ;
- ;============================================================
- cdrom_read proc near
-
- mov si,cx ;si = num sectors to read
- xchg dl,dh ;dl = drive num
- mov ch,dh ;ch = minute
- mov cl,ah ;cl = second
- mov dh,al ;dh = frame
- mov ah,READ_COOKED
- or di,di ;used cooked mode?
- je @f ; yes
- mov ah,READ_RAW ; no, read raw (2352 byte mode)
- @@: mov di,si
- ;
- ; ah - READ RAW/COOKED
- ; es:bx - transfer address
- ;ch,cl,dh - minute,second,frame
- ; di - num frames
- ;
- call CDREAD ;Perform the read operation
- jc @f ;was there a read error?
- ret ; no
- @@: ; yes, get an error code to return
- cmp ah,08h ;Seek error ??
- jne @f ; no, probably not
- mov ah,SEEK_CMD
- call CDREAD ;was it a sector not found error?
- mov cx,drverr_sector_not_found
- jnc read_failed ; yes
-
- mov cx,drverr_seek_error
- cmp ah,08h ;Seek error ??
- je read_failed ; yes
- @@:
- mov cx,drverr_drive_not_ready
- test ah,14h ;Drive not ready or Time out ??
- jnz read_failed ; yes
-
- mov cx,drverr_data_error
- cmp ah,80h ;Data error ??
- je read_failed ; yes
-
- mov cx,drverr_read_fault ;must be a read fault
-
- read_failed:
- mov ax,cx ;ax = error code
- or ax,(ERRBIT + DONEBIT)
- stc
- ret
-
- cdrom_read endp
-
-
- ;============================================================
- ;
- ; PREFETCH command
- ;
- ; Asynchronously read sectors into internal drive or driver controlled
- ; buffers.
- ;
- ; The cheap way to implement the prefetch command is with a seek since
- ; prefetching is considered advisory. If a drive, or the driver software,
- ; implement a "read-ahead" buffer, this entry point would initiate filling
- ; the buffer, in anticipation of a subsequent READ LONG command from the
- ; same location.
- ;
- ; Entry:
- ; dl:ax - redbook address for read
- ; cx - number of sectors to read
- ; es:bx - transfer address for data
- ; dh - drive number (0 based)
- ; di - read mode (0 = cooked, 1 = raw)
- ;
- ; Exit:
- ; carry set - error occurred, ax contains status word
- ; carry clear - read was successful
- ;
- ;============================================================
- cdrom_prefetch:
-
- ; fall through to the seek command.
- ;
-
- ;============================================================
- ;
- ; SEEK command
- ;
- ; Issue a seek command to the drive. This should cause the drive
- ; head to begin 'micro-seeking' at the indicated location in anticipation
- ; of receiving a command to read from there. If the drive has read-ahead
- ; buffers the action should actually cause a read operation to occur, and
- ; not really 'micro-seek' unless the buffer fills before subsequent read
- ; operations begin emptying it.
- ;
- ; Entry:
- ; dl:ax - redbook address for read
- ; dh - drive number (0 based)
- ;
- ; Exit:
- ; carry set - error occurred, ax contains status word
- ; carry clear - read was successful
- ; trashes cx
- ;
- ;============================================================
- cdrom_seek proc near
-
- xchg dl,dh ;dl = drive num
- mov ch,dh ;redbook minute
- mov cl,ah ;redbook second
- mov dh,al ;redbook frame
- mov ah,SEEK_CMD ;seek without wait
- call CDREAD ;Perform the seek operation
- jc @f ;was there an error?
- ret ; no
- @@:
- test ah,0Ah ; yes, was it a seek error?
- mov ax,(ERRBIT + DONEBIT + drverr_seek_error)
- jnz @f ; yes
- mov ax,(ERRBIT + DONEBIT + drverr_drive_not_ready)
- @@: ret
-
- cdrom_seek endp
-
-
- ;============================================================
- ;
- ; PLAY command
- ;
- ; Issue a play audio command to the drive.
- ;
- ; Entry:
- ; dx:ax - audio ending HSG logical sector number
- ; cx:di - audio start HSG logical sector number
- ; bx - drive num (0 based)
- ;
- ; Exit:
- ; carry set - error occurred, ax contains status word
- ; carry clear - play was successful
- ; trashes si,di
- ;
- ;============================================================
- cdrom_play_audio proc near
-
- ; convert locations to redbook and put in drive buffer
- ;
- lea si,cs:play_para ;parameter block for drive
- call hsg2red ;convert ending location
- mov cs:[si+3],dl
- xchg al,ah
- mov cs:[si+4],ax
- mov ax,di
- mov dx,cx
- call hsg2red ;convert starting location
- mov cs:[si],dl
- xchg al,ah
- mov cs:[si+1],ax
-
- mov dx,bx ;get drive num
-
- ; We need to force the power save off, the Amdek's are not doing this
- ; correctly
- ;
- ; cmp cs:pwr_save,0 ;drive turns off even when currently..
- ; je @f ;..playing audio!!!
-
- mov ax,(SET_POWER_SAVE shl 8)
- call CDREAD
- @@:
- mov ax,cs
- push es
- mov es,ax
- mov al,cs:audio_vol[bx] ;channel output (both, l, r or mute)
- mov di,bx ;preserve drive num
- mov bx,si ;es:bx -> drive's play parameters
- mov ah,AUDIO_L_R_CMD
- xor cx,cx
- call CDREAD ;play that audio
- mov bx,di ;restore drive num
- pop es
- jc play_error ;was the command successful?
- mov cs:loc_cnt,800 ; yes, clear up and return success..
-
- play_check: ; ..if the play takes that is
- call cdrom_drive_status
- jz play_drive_not_ready
- jc @f
- and al,1ch
- cmp al,04h
- je play_done
- @@: dec cs:loc_cnt
- jnz play_check
- mov ah,PAUSE_CMD ;the play command didn't take..
- call CDREAD ;..so perform a stop play..
- jmp short play_general_fail ;..and fail
-
- play_done:
- ;
- ; play request was successful, return carry clear, di = drive number
- ;
- ret
-
- play_error:
- test ah,14h ;time out or drive not ready error?
- jnz play_drive_not_ready ;
- test ah,08h ;was it a seek error ?
- jnz play_seek_error ; yes
- jmp short play_general_fail ; no
-
- play_drive_not_ready:
- ;
- ;also an entry point from RESUME AUDIO
- ;
- mov ax,(ERRBIT + DONEBIT + drverr_drive_not_ready)
- jmp short play_error_exit
-
- play_general_fail:
- ;
- ; this is also an entry point from RESUME AUDIO
- ;
- mov ax,(ERRBIT + DONEBIT + drverr_general_failure)
- jmp short play_error_exit
-
- play_seek_error:
- mov ax,(ERRBIT + DONEBIT + drverr_seek_error)
-
- play_error_exit:
- stc
- ret
-
- cdrom_play_audio endp
-
-
- ;============================================================
- ;
- ; STOP PLAY command
- ;
- ; Tell the drive not to play audio anymore.
- ;
- ; Entry:
- ; bx - drive num (0 based)
- ;
- ; Exit:
- ; carry set - error occurred, ax contains status word
- ; carry clear - stop/pause was successful
- ;
- ;============================================================
- cdrom_stop_audio proc near
-
- mov al,cs:pwr_save ;now that we're not playing audio..
- or al,al
- je @f
- mov ah,SET_POWER_SAVE ;..restore the power save feature
- mov dx,bx
- call CDREAD
- @@:
- mov ah,PAUSE_CMD
- call CDREAD ;perform the stop play
- mov cs:loc_cnt,800
- jnc @f ;error occurred?
- mov ax,(ERRBIT + DONEBIT + drverr_general_failure)
- ret ; yes
- @@: ; no, but make sure the command took
- call cdrom_drive_status
- jc @f
- test al,40h ;door open?
- jnz @f
- call status_mode_check
- jc @f
- cmp al,04h ;still playing?
- jne @f ; no
- dec cs:loc_cnt ; yes
- jnz @b
- @@:
- clc
- ret
-
- cdrom_stop_audio endp
-
-
- ;============================================================
- ;
- ; RESUME PLAY command
- ;
- ;============================================================
- ;
- ; this command is handled in the device independend code (MSCDEX.ASM).
- ;
-
-
- ;============================================================
- ;
- ; IOCTL INPUT commands
- ;
- ;============================================================
-
-
- ;----------------------------------------------------------------------
- ;
- ; IOCTL INPUT sub-function #1
- ;
- ; Return the HSG address of the current head location.
- ;
- ; Entry:
- ; bx - drive number to check head location
- ;
- ; Exit:
- ; carry set - an error occurred, ax contains the status word
- ; carry clear - dx:ax = HSG logical sector address of the drive head
- ;
- ;----------------------------------------------------------------------
- cdrom_location_head proc near
-
- xchg bx,di
- call cdrom_current_loc
- jc @f
- test ah,14h
- mov ax,(ERRBIT + DONEBIT + drverr_general_failure)
- jz @f ; is it really drive not ready?
- mov ax,(ERRBIT + DONEBIT + drverr_drive_not_ready) ; yep
- stc
- @@: xchg bx,di
- ret
-
- cdrom_location_head endp
-
-
- ;----------------------------------------------------------------------
- ;
- ; IOCTL INPUT sub-function #4
- ;
- ; Report current audio channel control settings. This will be the default
- ; arrangement of 1:1 input to output at full volume, otherwise it's whatever
- ; was last set by the Audio Channnel Control IOCTL Output subfunction #3.
- ;
- ; Hitachi volume settings are limited to ON or OFF, so the convention of
- ; FFh for ON, and 00h for OFF is used.
- ;
- ; Hitachi forces channel settings for 3 and 4 to default values.
- ;
- ; Entry:
- ; bx - drive number to report on.
- ; es:di - transfer area for audio channel info
- ;
- ; Exit:
- ; es:[di+0] - current input channel set for output channel 0 ( 0 or 1 )
- ; es:[di+1] - current volume set for output channel 0 ( 0 or -1 )
- ; es:[di+2] - current input channel set for output channel 1 ( 0 or 1 )
- ; es:[di+3] - current volume set for output channel 1 ( 0 or -1 )
- ; es:[di+4] - current input channel set for output channel 2 ( 0 )
- ; es:[di+5] - current volume set for output channel 2 ( 0 )
- ; es:[di+6] - current input channel set for output channel 3 ( 1 )
- ; es:[di+7] - current volume set for output channel 3 ( 0 )
- ;
- ;----------------------------------------------------------------------
- cdrom_audio_channel_info proc near
-
- mov al,cs:audio_vol[bx]
-
- or al,al ;are both channels on?
- jne @f ; no
- mov ax,0ffffh ; yes
- jmp short audio_channel_info_normal
- @@:
- cmp al,1 ;is left channel on, right off?
- jne @f ; no
- mov ax,0ffh ; yes
- jmp short audio_channel_info_normal
- @@:
- cmp al,2 ;is right channel on, left off?
- jne @f ; no, both channels must be off
- mov ax,0ff00h ; yes
- jmp short audio_channel_info_normal
- @@:
- xor ax,ax
-
- audio_channel_info_normal:
- mov cs:left_vol,al
- mov cs:right_vol,ah
- mov ax,cs
- mov ds,ax
- mov si,offset cs:audio_ch_work
- mov cx,audio_ch_work_size / 2
- cld
- rep movsw ;store from audio_ch_work structure
- ret
-
- cdrom_audio_channel_info endp
-
-
- ;----------------------------------------------------------------------
- ;
- ; IOCTL INPUT sub-function #5
- ;
- ; Return the version of the drive.
- ;
- ; Entry:
- ; bx - drive number
- ; es:di - transfer address for version string.
- ;
- ; Exit:
- ; carry clear - no error
- ; es:[di+0] = num bytes copied to es:[di+1]
- ; carry set - error
- ; es:[di+0] = 0
- ;
- ;----------------------------------------------------------------------
- cdrom_read_drive_bytes proc near
-
- mov es:io_num_bytes[di],52 ;return number of bytes read
- mov ah,GET_DRIVE_VERSION
- mov dx,bx ;drive number in dl
- mov bx,di ;transfer address in
- inc bx ;advance to 1st string character
- call CDREAD ;read version of CD-ROM drive
- jnc @f ;error getting version string?
- mov es:io_num_bytes[di],0 ; yes, say no bytes were read
- @@: ret ; no
-
- cdrom_read_drive_bytes endp
-
-
- ;----------------------------------------------------------------------
- ;
- ; IOCTL INPUT sub-function #6
- ;
- ; Return 32 bits of drive status information.
- ;
- ; These bits are constant ( 0x00000394 ):
- ; Bit:
- ; 2 - 1 (reads both cooked and raw mode)
- ; 3 - 0 (read only device)
- ; 4 - 1 (can play audio tracks and data read)
- ; 5 - 0 (no interleaving support)
- ; 7 - 1 (prefetching support)
- ; 8 - 1 (audio channel manipulation allowed)
- ; 9 - 1 (both HSG and redbook addressing support)
- ; 12 - 0 (no P-W subchannel support)
- ;
- ; Entry:
- ; bx - drive number
- ; es:di - transfer address
- ;
- ; Exit:
- ; carry - error occurred
- ; no " - dx:ax = device status
- ;
- ;----------------------------------------------------------------------
- cdrom_device_status proc near
-
- call cdrom_drive_status
- jnc @f
- jz device_status_error
- cmp al,8ah ;focus error
- jne device_status_error
- mov cx,0800h ;no disc in drive, door is closed
- jmp short device_status_door_closed
- @@: ;no error so far
- xor cx,cx ;cx is temp device status bit field
- test al,20h ;disk changed ?
- jz @f ; no
- mov cs:disc_changed[bx],1 ; yes, set the disc changed flag
- @@: test al,40h ;is the door open?
- jz device_status_door_closed ; nope
- mov cs:disc_changed[bx],1 ; yep, no disc in drive, door open
- or cx,801h
-
- device_status_door_closed:
- mov ax,(PREVENT_ALLOW_CMD shl 8) ;al = 0 (read lock mode)
- mov dx,bx ;dx = drive number
- call CDREAD
- jc device_status_error ;time out
- test al,1 ;media is removable??
- jnz @f ; nope, door is locked
- or cx,2 ; yes, door is unlocked
- @@: or cx,394h ;set constant Hitachi device status
- mov ax,cx
- xor dx,dx
- clc
-
- device_status_exit:
- ret
-
- device_status_error:
- stc ;time out or drive not ready error
- jc device_status_exit
-
- cdrom_device_status endp
-
-
- ;----------------------------------------------------------------------
- ;
- ; IOCTL INPUT sub-function #7
- ;
- ; Return CD-ROM sector size for the passed read mode. Since this must be
- ; 2048 for cooked, and 2352 for raw, it's handled by device independent code.
- ;
- ;----------------------------------------------------------------------
- ;----------------------------------------------------------------------
- ;
- ; IOCTL INPUT sub-function #8
- ;
- ; Return number of CD-ROM sectors available on the disc. This is the
- ; location of the lead out track in binary. For example a lead-out track
- ; at 31:14.63 would yield (31 * 60 * 75) + (14 * 75) + 63 = 140613.
- ;
- ; Entry:
- ; bx - drive number
- ; es:di - transfer address
- ;
- ; Exit:
- ; carry - error occurred, ax contains status code
- ; no " - dx:ax = volume size
- ;
- ; trashes bx,cx,si,ds
- ;
- ;----------------------------------------------------------------------
- cdrom_volume_size proc near
- push es ;preserve the xfer address
- push di
- sub sp,6 ;reserve a buffer for diskinfo
- mov ax,ss
- mov es,ax
- mov di,sp ;es:di points to buffer for diskinfo
- call cdrom_audio_diskinfo
- jnc @f ;error getting lead-out track?
- add sp,6 ;revert the stack
- stc ;set the error
-
- volume_size_exit:
- pop di ;revert the xfer addr
- pop es
-
- ret
-
- @@:
- mov bp,sp
- mov dx,[bp+4] ;no, get redbook addr of lead-out...
- mov ax,[bp+2]
- call red2hsg ;...convert it to HSG addr
-
- sub ax,1 ; the lead out addr is 1 greater than
- sbb dx,0 ; the last sector
-
- add sp,6 ;revert the stack
- clc
- jmp short volume_size_exit
-
- cdrom_volume_size endp
-
-
- ;----------------------------------------------------------------------
- ;
- ; IOCTL INPUT sub-function #9
- ;
- ; Entry:
- ; bx = drive num
- ;
- ; Exit:
- ; carry set - error occurred, al is invalid
- ; carry clear - al = 1 - not changed, -1 - changed, 0 - can't tell
- ; trashes cl
- ;
- ;----------------------------------------------------------------------
- cdrom_media_changed proc near
-
- mov cl,1 ;assume didn't changed
- call cdrom_drive_status
- jc @f ;drive not ready?
- mov al,cs:disc_changed[bx] ;get disc change flag..
- mov cs:disc_changed[bx],0 ;..and reset it (now they know)
- or al,al ; disc changed?
- jz @f ; no, go report it
- mov cl,-1 ; maybe, make sure..
- cmp al,1 ; ..disc changed?
- je @f ; yep
- xor cl,cl ; no, don't know what's going on
- @@: mov al,cl ;return media changed flag in al
- ret
-
- cdrom_media_changed endp
-
-
- ;----------------------------------------------------------------------
- ;
- ; IOCTL INPUT sub-function #10
- ;
- ; Report the binary value of the lowest and highest track, and the redbook
- ; address of the lead-out track as recorded in the Q-channel of the
- ; lead-in track.
- ;
- ; Note Hitachi code below will cause a seek to lead-in area to get this
- ; information, only if not previously reported for the current disc.
- ;
- ; Entry:
- ; bx - drive num
- ; es:di - application buffer for disk info
- ;
- ; Entry:
- ; carry set - error occurred, ax contains status word
- ; carry clear - first track, last track, start of lead-out copied
- ; trashes bx,cx,si,di,ds
- ;
- ;----------------------------------------------------------------------
- cdrom_audio_diskinfo proc near
-
- mov cs:a_flag,0
-
- get_audio_track_entry:
- ;
- ; a_flag: 0 - called from audio_diskinfo
- ; 1 - called from audio_trackinfo
- ;
- call cdrom_drive_status
- jnc @f ;not ready error?
-
- audio_diskinfo_not_ready:
- mov ax,(ERRBIT + DONEBIT + drverr_drive_not_ready)
-
- audio_diskinfo_error:
- stc
- ret
- @@:
- mov scans,SCAN_COUNT ;scan default number til see a0/a1/a2
- mov ax,es ;preserve application's..
- mov word ptr app_xfer_buffer+2,ax ;..transfer..
- mov word ptr app_xfer_buffer,di ;..address
- mov dx,bx
- mov bp,offset toc_table
- mov ax,cs
- mov es,ax
- mov ds,ax
- mov bx,offset qbuf
- ;
- ; register usage in loops below:
- ;
- ; dx = drive number for all drive calls below
- ; bp = toc_table base for resetting di
- ; bx = qbuf base for resetting si and to pass to the drive
- ; ds:si = current offset into qbuf (Qchannel buffer)
- ; es:di = current offset into toc_table (table of contents buffer)
- ;
- cmp dl,cs:toc_drive ;do we already know this toc?
- jne @f ; no, have to init toc_table
- jmp audio_diskinfo_same ; yes
- @@:
- mov cs:toc_drive,0ffh ;reset drive flag (none current)
- mov si,bp
- add si,point_x ;get loc of first point_x
- mov cx,3+99 ;zero all point's to tell when all..
- xor ax,ax ;..track locations have been init'd
- @@: mov [si],al
- add si,size _QchanInfo
- loop @b
- ;
- ; Head of retry loop
- ;
- mov i1,RETRY_COUNT
-
- audio_diskinfo_i1_loop:
- mov ah,SEEK_LEADIN_CMD ;Seek to lead-in track
- call CDREAD
- jc audio_diskinfo_not_ready
- ;
- ; init Q-channel info in the last iteration to a value we won't ever see
- ;
- mov last_point,0ffh
- ;
- ; head of loop scanning for new entries
- ;
- mov i2,0
-
- audio_diskinfo_i2_loop:
- mov cs:loc_cnt,900 ;about 10 seconds
-
- audio_diskinfo_loop_Q:
- mov ah,READ_Q_CMD ;read 10 Q-channel bytes
- call CDREAD
- jc audio_diskinfo_not_ready
- mov al,[bx].point_x ;get which Q-channel byte this is
- cmp al,last_point ;is it the same as the last iteration?
- je audio_diskinfo_next_Q ; yep, keep looking
- mov cl,[bx].ctrl_adr ; nope, get ctrl info
- cmp cl,0FFh ;still seeking to lead_in?
- je audio_diskinfo_next_Q ; yes, try again
- and cl,0Fh ; no, mask off ADR
- cmp cl,1 ;is it a TOC entry?
- jne audio_diskinfo_next_Q ; no, ignore ADR = 2 or 3
- mov last_point,al ; yes, got a new entry, remember it
- cmp [bx].tno,0 ;still in the lead-in track?
- jne audio_diskinfo_done ; no, get out and try again
- cmp al,0A0h ; yes, is it one of a0/a1/a2?
- je @f ; yes
- cmp al,0A1h
- je @f ; yes
- cmp al,0A2h
- je @f ; yes
- ;
- ; not a0/a1/a2, must be audio track info, convert to binary
- ;
- call bcd2bin
- jc audio_diskinfo_done ;bogus value, get out, try again
- ;
- ; first 3 entries in toc_table are for a0/a1/a2
- ; other 99 are for track info. track 1 starts at offset 3
- ;
- add ax,3 - 1 ;skip over first/last track record
- jmp short audio_diskinfo_store_qbuf
-
- audio_diskinfo_next_Q:
- dec cs:loc_cnt
- jnz audio_diskinfo_loop_Q
- jmp audio_diskinfo_next_i1 ;still didn't find a0/a1/a2, go retry
- @@:
- ;
- ; Handle a0/a1/a2 entries here.
- ; If we see a2, check if a0 and a1 already seen
- ; If both seen, we know how many tracks are on the CD
- ; so we can decrease the number of entries we have to read
- ;
- push ax
- cmp al,0A2h ;is this a2 entry?
- jne @f ; no, handle normal
- mov di,bp ; yes, check if a0 and a1 entries seen
- cmp [di].point_x,0 ;entry is seen if point_x is non-zero
- je @f
- cmp [di + size _QchanInfo].point_x,0
- je @f
- ;
- ; a0 and a1 are read, calculate how many more entries we have
- ; to read before getting the entire TOC
- ;
- mov al,[di + size _QchanInfo].pmin
- call bcd2bin
- mov cx,ax
- mov al,[di].pmin
- call bcd2bin
- sub cx,ax
- add cx,1+3
- mov scans,cx ;last - first + 1 + 3 (for a0/a1/a2)
- @@:
- pop ax ;restore a0/a1/a2
- sub al,0A0h ;calc offset into toc_table
-
- audio_diskinfo_store_qbuf:
- mov cx,size _QchanInfo
- imul cl ;ax is offset from base of toc_table
- mov di,bp
- add di,ax ;es:di -> where to store new entry at
- mov si,bx ;ds:si -> new entry
- mov cx,(size _QchanInfo) / 2;copy 10 bytes
- rep movsw
-
- mov cx,scans ;check if we are done scanning table
- cmp i2,cx ;copied > default or num in table?
- jae audio_diskinfo_done ; yep, exit
- inc i2 ; nope
- jmp audio_diskinfo_i2_loop
-
- audio_diskinfo_done:
- ;
- ; make sure all qchannel entries are read in and are valid
- ;
- ; first see if a0/a1/a2 are valid
- ;
- mov di,bp ;get back base of toc_table
- cmp [di].point_x,0
- je audio_diskinfo_not_done
- cmp [di + size _QchanInfo].point_x,0
- je audio_diskinfo_not_done
- cmp [di + (size _QchanInfo * 2)].point_x,0
- je audio_diskinfo_not_done
- ;
- ; a0/a1/a2 valid, we can calculate the number of entries in toc_table
- ; where number of entries is last - (first - 1)
- ;
- mov al,[di + size _QchanInfo].pmin
- call bcd2bin
- mov cx,ax ;cx = last
- mov al,[di].pmin ;ax = first
- call bcd2bin
- dec ax
- sub cx,ax ;cx is num entries, ax is first - 1
- ;
- ; Calc offset in toc_table to start scanning from:
- ; (offset toc_table) + ((first-1+3) * size _QchanInfo)
- ;
- add ax,3
- mov dh,size _QchanInfo
- imul dh
- add di,ax
- add di,point_x ;add offset of point_x
- @@: ;verify that all point_x's are filled
- cmp byte ptr [di],0
- jz audio_diskinfo_not_done
- add di,(size _QchanInfo)
- loop @b
- jmp short audio_diskinfo_valid
-
- audio_diskinfo_not_done:
- ;
- ; at least one Q-channel entry isn't valid
- ;
- cmp i2,250 ;get another Q-channel entry?
- jae audio_diskinfo_next_i1 ; no, retry from lead-in track
- jmp audio_diskinfo_i2_loop ; yes
-
- audio_diskinfo_next_i1:
- dec i1 ;ok to retry at lead-in track again?
- jz @f ; nope, drive must not be ready
- jmp audio_diskinfo_i1_loop ; yes, give the drive another chance
- @@:
- mov ah,PAUSE_CMD
- call CDREAD
- jmp audio_diskinfo_not_ready
-
- audio_diskinfo_valid:
- mov ah,PAUSE_CMD
- call CDREAD ;perform the pause
- jnc audio_diskinfo_same
- jmp audio_diskinfo_not_ready;geez, and we almost made it too
-
- audio_diskinfo_same:
- ;
- ; The table is complete, copy the a0/a1/a2 results back to user
- ;
- mov es,word ptr app_xfer_buffer+2 ; restore app's transfer addr
- mov di,word ptr app_xfer_buffer
-
- mov cs:toc_drive,dl ;now we know this toc
- ;
- ; if really called from audio_trackinfo return there
- ;
- cmp cs:a_flag,0
- je @f ; nope, it's audio_diskinfo time
- jmp short audio_trackinfo_return ; yep, we're done
- @@:
- mov si,(offset toc_table + pmin) ;ds:si is addr of a0 pmin
- mov al,[si] ;get first track no (a0)
- call bcd2bin
- stosb ;copy first track number
- mov al,[si + size _QchanInfo];get last track no (a1)
- call bcd2bin
- stosb ;copy last track number
- add si,size _QchanInfo * 2 ;ds:si is addr of a2 pmin/psec/pframe
- mov dl,ds:[si] ;Convert from bcd to binary red book
- mov ax,ds:[si+1]
- xchg al,ah
- call bcd2red
- stosw ;copy address of lead-out track
- mov ax,dx
- stosw
- clc
- ret
-
- cdrom_audio_diskinfo endp
-
-
- ;----------------------------------------------------------------------
- ;
- ; IOCTL INPUT sub-function #11
- ;
- ; Return the redbook address of the passed binary track number, and the
- ; track control information byte.
- ;
- ; Takes the track number desired and looks up the toc_table information
- ; If the disc has been changed since the last time this information was
- ; retrieved the toc_table will be rebuilt.
- ;
- ; Entry:
- ; bx - drive num
- ; es:di - application buffer for track info
- ;
- ; Entry:
- ; carry set - error occurred, ax contains status word
- ; carry clear - starting point of track and control info copied
- ; trashes bx,cx,si,di,ds
- ;
- ;----------------------------------------------------------------------
- cdrom_audio_trackinfo proc near
-
- mov cs:a_flag,1
- jmp get_audio_track_entry
-
- audio_trackinfo_return:
- ;
- ; returns with ds set to cs
- ;
- xor cx,cx
- mov cl,es:[di] ;cx = passed track number
- inc di ;get to redbook address xfer area
- mov si,offset toc_table
- ;
- ; make sure the track they're asking about is not before the first
- ; one, or after the last one
- ;
- mov al,[si].pmin
- call bcd2bin
- cmp cl,al ;before the first track?
- jb audio_trackinfo_error ; yes
- mov al,[si+size _QchanInfo].pmin
- call bcd2bin
- cmp cl,al ;after the last track?
- ja audio_trackinfo_error ; yes
- dec cx ; no, make 1->0,...,99->98
- ;
- ; offset into toc_table for inquired track number
- ;
- mov ax,size _QchanInfo
- imul cx
- add ax,size _QchanInfo * 3 ;skip a0/a1/a2 entries
- add si,ax ;ds:si addr of entry we want
- mov dl,[si].pmin
- mov ah,[si].psec
- mov al,[si].pframe
- call bcd2red
- mov es:[di],ax
- mov es:[di+2],dx
- mov al,[si].ctrl_adr ;get ctrl info for track
- mov es:[di+4],al
- clc
- ret
-
- audio_trackinfo_error:
- mov ax,(ERRBIT + DONEBIT + drverr_general_failure)
- stc
- ret
-
- cdrom_audio_trackinfo endp
-
-
- ;----------------------------------------------------------------------
- ;
- ; IOCTL INPUT sub-function #12
- ;
- ; Return the current Q-channel address in redbook.
- ;
- ; Note the operation of this function *should not* change the current
- ; drive status, as it can be used to monitor the current head location.
- ; Therefore, it should be successful even if the drive is currently idle.
- ;
- ; Note the CONTROL/ADR and POINT/Index bytes are returned verbatim,
- ; and if ADR is not 1, the address of the head location is not translated
- ; to redbook since in this case it is either the UPC bytes or.
- ;
- ; Entry:
- ; bx - drive num
- ; es:di - application buffer for Qchannel info
- ;
- ; Exit:
- ; carry set - error occurred, ax contains status word
- ; carry clear - Qchannel info was copied
- ; trashes bx,cx,si,di,bp,ds
- ;
- ;----------------------------------------------------------------------
- cdrom_audio_Qchannel proc near
-
- mov cs:scans,CNT3 ;set loop limit
- mov dx,bx ;dx = drive number
- mov ax,cs
- mov ds,ax
- mov si,offset cs:qbuf
- ;
- ; ds:si - qbuf
- ; es:di - xfer addr
- ; dx - drive num
-
- cda_Qchannel_retry:
- push es
- mov ax,cs
- mov es,ax
- mov bx,si
- mov ah,READ_Q_CMD
- call CDREAD ;read subcode-Q (TOC)
- pop es ;restore xfer segment address
- jnc @f
-
- cda_Qchannel_error:
- mov ax,(ERRBIT + DONEBIT + drverr_drive_not_ready)
- stc
- ret
- @@:
- dec cs:scans ;timeout?
- jz cda_Qchannel_error ; yes
-
- mov al,[si].ctrl_adr
- cmp al,0FFh ;Invalid CONTROL/ADR??
- je cda_Qchannel_retry ; yes
- ;
- ; set cx = flag for whether to xlat times to redbook
- ; no xlat is necessary if ADR is 2 (UPC bytes), or ADR is 3 ( ? )
- ;
- mov cx,1 ;assume xlat
- and al,0Fh ;did we read a qchannel address..
- cmp al,01h ;..in that sector?
- je @f ; yes
- xor cx,cx ; no, don't need to xlat to redbook
- @@:
- ;
- ; copy Qchannel buffer to the request header (xlat BCD addresses if required)
- ;
- movsb ;CONTROL and ADR byte
- movsw ;track num byte, and point_x byte
- mov bp,2 ;copy two times (running and absolute)
-
- cda_Qchannel_disk_time:
- lodsb
- mov dl,al
- lodsw
- or cx,cx
- je @f
- xchg al,ah
- call bcd2red
- @@: xchg al,ah
- xchg al,dl
- stosb
- xchg al,dl
- stosw
- dec bp
- jz cda_Qchannel_exit
- movsb ;copy the zero
- jmp short cda_Qchannel_disk_time
-
- cda_Qchannel_exit:
- clc
- ret
-
- cdrom_audio_Qchannel endp
-
-
- ;----------------------------------------------------------------------
- ;
- ; IOCTL INPUT sub-function #13
- ;
- ; Returns the sub-channel information from the contiguous frames (sectors)
- ; requested starting at the passed redbook address. The sub-channels are
- ; not decoded, that is, P is the MSB and W is the LSB in each byte.
- ;
- ; This command is be supported by Hitachi drive hardware.
- ;
- ; Entry:
- ; bx - drive num
- ; es:di - application buffer for sub-channel bytes
- ;
- ; Exit:
- ; carry set - error occurred, ax contains status word
- ; carry clear - sub-channel bytes were copied
- ;
- ;----------------------------------------------------------------------
- cdrom_audio_Subchannel proc near
-
- ; This command should be supported!
- ;
- mov ax,(ERRBIT + DONEBIT + drverr_unknown_command)
- stc
- ret
-
- cdrom_audio_Subchannel endp
-
-
- ;----------------------------------------------------------------------
- ;
- ; IOCTL INPUT sub-function #14
- ;
- ; Return the Universal Product Code of the disc. This is located in 10
- ; contiguous bytes of the Q-channel (ie., in one frame out of every 100),
- ; and identified with an ADR value of 2.
- ;
- ; Entry:
- ; bx - drive num
- ; es:di - application buffer for UPC bytes
- ;
- ; Exit:
- ; carry set - error occurred, ax contains status word
- ; carry clear - UPC bytes were copied
- ;
- ;----------------------------------------------------------------------
- cdrom_upc_code proc near
-
-
- ; If the head is not moving, the upc information won't be a part of the
- ; Qchannel information, so we seek to the lead in track
-
- call cdrom_drive_status ;busy with audio?
- jc upc_disk_error ; drive not ready
- and al,04h ; audio playing?
- jnz @f ; yes? continue w/init
-
- mov ah,SEEK_LEADIN_CMD ; audio not playing?
- call CDREAD ; Seek to lead in
- jc upc_disk_error
-
- @@:
- mov cs:scans, UPC_COUNT ; Repeat count
- mov dx,bx
- mov ax,cs
- mov ds,ax
- mov si,offset cs:qbuf
-
- ;
- ; ds:si - qbuf
- ; es:di - xfer addr
- ; dx - drive num
- ;
-
- upc_retry: ; loop to retry
-
- push es
- mov ax,cs
- mov es,ax
- mov bx,si
- mov ah,READ_Q_CMD ; Call the Qchannel read
- call CDREAD
- pop es
- jnc @f
-
- upc_disk_error: ; Problem with the read
- mov ax,(ERRBIT + DONEBIT + drverr_drive_not_ready)
- stc
- ret
-
- @@:
- mov al,[si].ctrl_adr ; ADR == 2 means this
- and al,0fh ; subcode block has UPC
- cmp al,2
- je upc_return ; yes? return the block
-
- dec cs:scans
- jnz upc_retry ; try again or fall through
-
- ; UPC code was missed or non-existant
- ;
- ; fall through, returns sector_not_found
- ;
- mov ax,(ERRBIT + DONEBIT + drverr_sector_not_found)
- stc
- ret
-
- ; returns upc info
-
- upc_return:
- mov cx,(size _QchanInfo /2) ; Word copy the UPC information
- rep movsw ; into the xfer
- clc
- ret
-
- cdrom_upc_code endp
-
-
- ;----------------------------------------------------------------------
- ;
- ; IOCTL INPUT sub-function #15
- ;
- ;
- ; Return audio status information. This is called from the device
- ; independent code to ask whether the drive door is open. The PLAY AUDIO
- ; command should lock the drive door closed, but if this is overridden (if
- ; the door can be opened manually) this call should check if the door is
- ; open and return carry set if it is.
- ;
- ; Entry:
- ; bx - drive num
- ;
- ; Exit:
- ; carry set - door is open or error occurred
- ; carry clear - door is closed
- ;
- ;----------------------------------------------------------------------
- cdrom_audio_status_info proc near
-
- call cdrom_drive_status ;error occurred?
- jc @f ; yes
- test al,40h ; no, door open?
- jz @f ; no
- stc ; yes
- @@: ret
-
- cdrom_audio_status_info endp
-
-
- ;============================================================
- ;
- ; IOCTL OUTPUT commands...
- ;
- ;============================================================
-
- ;----------------------------------------------------------------------
- ;
- ; IOCTL OUTPUT sub-function #0
- ;
- ; Unlock the drive door and eject the disc.
- ;
- ; Note that after successful completion of this command the status bit
- ; in the device status word should report the door as being open until the
- ; user has inserted a disc and closed the door (so the door open bit
- ; can be monitored until this has occurred).
- ;
- ; Entry:
- ; bx - drive num
- ;
- ; Exit:
- ; carry set - error occurred, ax contains status word
- ; carry clear - ejected OK
- ;
- ;----------------------------------------------------------------------
- cdrom_eject proc near
-
- mov dx,bx ;dx = drive number
- mov ax,( (PREVENT_ALLOW_CMD shl 8) + 2 )
- call CDREAD ;unlock the door please
- jc cdrom_eject_drive_not_ready
- test al,01h ;media is removable?
- jz @f ; yes (door currently unlocked)
- mov ax,(ERRBIT + DONEBIT + drverr_invalid_disc_change)
- stc
- jc cdrom_eject_exit
- @@:
- mov ah,OPENDOOR_CMD
- call CDREAD ;Open door
- ;
- ; if carry is clear no error occurred and what's in ax is ignored
- ;
- cdrom_eject_drive_not_ready:
- mov ax,(ERRBIT + DONEBIT + drverr_drive_not_ready)
-
- cdrom_eject_exit:
- ret
-
- cdrom_eject endp
-
-
- ;----------------------------------------------------------------------
- ;
- ; IOCTL OUTPUT sub-function #1
- ;
- ; Unlock/lock the drive door.
- ;
- ; Entry:
- ; bx - drive num
- ; al - lock/unlock code byte (0 - unlock door, 1 - lock door)
- ;
- ; Exit:
- ; carry set - error occurred, ax contains status word
- ; carry clear - requested locking function completed OK
- ;
- ;----------------------------------------------------------------------
- cdrom_lock_door proc near
-
- mov dx,bx ;dx = drive number
- cmp al,1 ;lock the door?
- je @f ; yes
- mov al,2 ; no
- @@:
- mov ah,PREVENT_ALLOW_CMD ;al = 1 - set lock mode, or
- call CDREAD ; = 2 - set unlock mode
- ;
- ; if carry is clear no error occurred and what's in ax is ignored
- ;
- mov ax,(ERRBIT + DONEBIT + drverr_drive_not_ready)
- ret
-
- cdrom_lock_door endp
-
-
- ;----------------------------------------------------------------------
- ;
- ; IOCTL OUTPUT sub-function #2
- ;
- ; Tell the drive to reset and re-initialize itself. What happens here
- ; is, of course, entirely driver/hardware dependent.
- ;
- ; Entry:
- ; bx - drive num
- ;
- ; Exit:
- ; carry set - error occurred, ax contains status word
- ; carry clear - reset OK
- ;
- ;----------------------------------------------------------------------
- cdrom_reset_drive proc near
-
- mov dx,bx ;dx = drive number
- mov ah,RESET_CMD
- call CDREAD
- ;
- ; if carry is clear no error occurred and what's in ax is ignored
- ;
- mov ax,(ERRBIT + DONEBIT + drverr_drive_not_ready)
- ret
-
- cdrom_reset_drive endp
-
-
- ;----------------------------------------------------------------------
- ;
- ; IOCTL OUTPUT sub-function #3
- ;
- ; Control audio channel output.
- ;
- ; Drives that support audio volume control distribute the number of settings
- ; continuously across 256 values (eg. 16 settings become 0, 16, 32, ...).
- ;
- ; Drives than can't swap channels ignore channel swapping unless requested
- ; to play both channels in one, in which case the other is suppressed.
- ;
- ; Drives that don't support four audio channels should ignore setting
- ; specified for the second pair of channels.
- ;
- ; Entry:
- ; bx - drive num
- ; cl - output channel for input channel 0
- ; ch - channel 0 volume setting
- ; dl - output channel for input channel 1
- ; dh - channel 1 volume setting
- ; si - lo byte = output channel for input channel 2
- ; hi byte = channel 2 volume
- ; di - lo byte = output channel for input channel 3
- ; hi byte = channel 3 volume
- ;
- ; Exit:
- ; carry set - error occurred, ax contains status word
- ; carry clear - reset OK
- ;
- ;----------------------------------------------------------------------
- cdrom_audio_channel_ctrl proc near
-
- ; init the volume settings
- ;
- mov cs:left_vol,ch
- mov cs:right_vol,dh
- ;
- ; see if they are playing both channels in one
- ; (Hitachi doesn't support redirecting channels so simulates it)
- ;
- cmp cl,dl
- jne audio_channel_ctrl_set ; nope
- cmp cl,1 ; yes, but is it 0 or 1?
- ja audio_channel_ctrl_set ; no
- je @f ; yes, shut off channel 0?
- mov cs:left_vol,0 ; yes
- jmp short audio_channel_ctrl_set
- @@: mov cs:right_vol,0 ; no, shut off channel 1
-
- audio_channel_ctrl_set:
- ;
- ; setup the output volume levels code in al
- ;
- mov ch,cs:left_vol
- mov cl,cs:right_vol
- mov al,3 ;assume both channels are off
- or ch,ch ;is left channel on?
- jz @f ; no
- and al,1 ; yes
- @@: or cl,cl ;is right channel on?
- jz @f ; no
- and al,2 ; yes, shut off bit 0
- @@:
- mov cs:audio_vol[bx],al
- mov dx,bx ;dx = drive number
- mov ah,AUDIO_CHANNEL_CTL ;al = volume settings
- call CDREAD
- ;
- ; if carry is clear no error occurred and what's in ax is ignored
- ;
- mov ax,(ERRBIT + DONEBIT + drverr_drive_not_ready)
- ret
-
- cdrom_audio_channel_ctrl endp
-
-
- ;----------------------------------------------------------------------
- ;
- ; IOCTL OUTPUT sub-function #4
- ;
- ; Write bytes directly to the CD-ROM drive.
- ;
- ; This routine is provided to allow device and/or driver dependent
- ; information (not addressed elsewhere in the MSCDEX device driver spec)
- ; to be sent by an application.
- ;
- ;
- ; Entry:
- ; bx - drive num
- ; es:di - application buffer for drive specific data
- ;
- ; Exit:
- ; carry set - error occurred, ax contains status word
- ; carry clear - set drive data OK
- ;
- ;----------------------------------------------------------------------
- cdrom_write_drive_ctrl proc near
-
- mov al,es:ioo_wrdev_top[di]
- or al,al ;top data byte=0?
- jne write_drive_ctrl_unknown_command; no
- ; yes, 1st 3 bytes = 'HIT'?
- cmp byte ptr es:ioo_wrdev_char[di],'H'
- jne write_drive_ctrl_unknown_command
- cmp word ptr es:ioo_wrdev_char[di+2],'TI'
- jne write_drive_ctrl_unknown_command; no
- push si ; yes
- push di
- push es
- mov ax,es:ioo_wrdev_data[di] ;setup registers
- mov bx,es:ioo_wrdev_data[di+2]
- mov cx,es:ioo_wrdev_data[di+4]
- mov dx,es:ioo_wrdev_data[di+6]
- mov si,es:ioo_wrdev_data[di+8]
- push ax
- mov ax,es:ioo_wrdev_data[di+12]
- mov di,es:ioo_wrdev_data[di+10]
- mov es,ax
- pop ax
- call CDREAD
- pop es
- pop di
- pop si
- ;
- ; if carry is clear no error occurred and what's in ax is ignored
- ;
- write_drive_ctrl_drive_not_ready:
- mov ax,(ERRBIT + DONEBIT + drverr_drive_not_ready)
- ret
-
- write_drive_ctrl_unknown_command:
- mov ax,(ERRBIT + DONEBIT + drverr_unknown_command)
- ret
-
- cdrom_write_drive_ctrl endp
-
-
- ;----------------------------------------------------------------------
- ;
- ; IOCTL OUTPUT sub-function #5
- ;
- ; Close the drive door. This is the logical complement to the eject
- ; command (IOCTL OUTPUT sub-function #0)
- ;
- ; Entry:
- ; bx - drive num
- ;
- ; Exit:
- ; carry set - error occurred, ax contains status word
- ; carry clear - closed tray OK
- ;
- ;----------------------------------------------------------------------
- cdrom_close_tray proc near
-
- mov dx,bx
- mov ah,CLOSEDOOR_CMD
- call CDREAD ;Open door
- mov ax,(ERRBIT + DONEBIT + drverr_drive_not_ready)
- ;
- ; if carry is clear no error occurred and what's in ax is ignored
- ;
- ret
-
- cdrom_close_tray endp
-
-
- ;============================================================
- ;
- ; INPUT FLUSH command
- ;
- ; Free all input buffers and clear any pending requests.
- ;
- ;============================================================
- cdrom_input_flush proc near
-
- ; This device driver doesn't buffer any I/O and all I/O requests are
- ; synchronous calls
- ;
- stc
- mov ax,(ERRBIT + DONEBIT + drverr_unknown_command)
- ret
-
- cdrom_input_flush endp
-
-
- ;======================================================================
- ;
- ; DEVICE OPEN command
- ;
- ; Indicates to the device driver that an application is beginning to use it.
- ;
- ;======================================================================
- cdrom_device_open proc near
-
- clc
- ret
-
- cdrom_device_open endp
-
-
- ;======================================================================
- ;
- ; DEVICE CLOSE command
- ;
- ; Indicates to the device driver that an application is beginning to use it.
- ;
- ;======================================================================
- cdrom_device_close proc near
-
- clc
- ret
-
- cdrom_device_close endp
-
-
- ;***************************************************************
- ;
- ; Device dependent helper functions.
- ;
- ;***************************************************************
-
-
- ;---------------------------------------------------------------
- ;
- ; cdrom_current_loc
- ;
- ; Return the current location of the drive head as a HSG sector address.
- ; This must be implemented using the Q-channel since the caller must
- ; be able to expect the successful operation of this routine will not
- ; interrupt audio playing.
- ;
- ; Entry:
- ; bx - drive number
- ;
- ; Exit:
- ; trashes cx
- ; Carry set - an error occurred, ax contains drive status bits
- ; Carry clear - dx:ax = current HSG logical sector location of drive head.
- ;
- ;---------------------------------------------------------------
- cdrom_current_loc proc near
-
- push bx
-
- mov cs:loc_cnt,800 ;read up to 800 tracks
-
- loc_status:
- call cdrom_drive_status ;returns with dx = drive number
- jc loc_error
- test al,40h ;open?
- jnz loc_error
- call status_mode_check
- jnc @f
-
- mov ah,STATUS_CMD
- call CDREAD
- jc loc_error
- test al,02h ;drive ready?
- jz @f ; yes
-
- loc_next:
- dec cs:loc_cnt ; no, not ready, give more time?
- jnz loc_status ; yes
- ; no
- loc_error: ;read micro-RAM into 'BUF'
- mov ah,04h
- stc
- jmp short loc_exit
- @@:
- ;
- ; the drive is ready, read the Q-channel to get the head location
- ;
- push es ;(10)
- mov ax,cs
- mov es,ax
- mov ax,(READ_Q_CMD shl 8)
- xor cx,cx
- mov bx,offset cs:BUF
- call CDREAD ;Get 10 Q-channel bytes
- pop es ;(9)
- jc loc_error
-
- mov al,cs:[bx].ctrl_adr
- and al,0Fh
- cmp al,1 ;ADR=1?
- jne loc_next ; no
-
- mov al,cs:[bx].tno
- or al,al ;TNO=0?
- jnz @f ; no, go calculate frame (sector)
- cbw ; yep, we're at address 0
- mov dx,ax
- jmp short loc_exit
- @@:
- ;
- ; calculate the HSG sector address
- ;
- mov al,cs:[bx].pmin
- call bcd2bin
- mov cl,60
- mul cl
- mov cx,ax ;cx = minutes * (60 sec/min)
- mov al,cs:[bx].psec
- call bcd2bin
- add cx,ax ;cx += num seconds
- mov ax,cx
- cmp ax,99*60 ;within 99 minute?
- jbe @f ; yes
- xor ax,ax ; no, invalid address!
- mov dx,ax
- jmp short loc_exit
- @@:
- mov dx,75
- mul dx ;total whole seconds *= 75 frames/sec
- mov cx,ax
- mov al,cs:[bx].pframe
- call bcd2bin ; += current frame address (0..75)
- add ax,cx
- adc dx,0 ;dx:ax = frame number head is now at
- sub ax,150 ;convert to HSG sectors
- sbb dx,0 ;leaves carry clear if no error
-
- loc_exit:
- pop bx
- ret
-
- cdrom_current_loc endp
-
-
- ;---------------------------------------------------------------
- ;
- ; cdrom_drive_status
- ;
- ; Return status of the drive. Also flags toc_table as invalid if the
- ; disc has changed or the requested drive is different from last time.
- ;
- ; This routine is used by device independent and device dependent code.
- ;
- ; When called from the device independent get_drive_status in MSCDEX.ASM
- ; the carry flag is expected to indicate whether the drive is ready.
- ;
- ; When called from withing CD.ASM other information may be returned.
- ;
- ; Entry:
- ; bx - drive num (0 based)
- ;
- ; Exit:
- ; trashes dx (leaves set to drive number)
- ; carry set -> drive not ready error
- ; zero set -> time out error
- ; ax -> 7 6 5 4 3 2 1 0
- ; | | | | | | | |
- ; | | | | | | | - time out error
- ; | | | | | | |
- ; | | | | | | --- media changed
- ; | | | | | |
- ; | | | | | ----- playing audio
- ; | | | | |
- ; | | | | ------- ?
- ; | | | |
- ; | | | --------- ?
- ; | | |
- ; | | ----------- drive door is open
- ; | |
- ; | ------------- ?
- ; |
- ; --------------- drive not ready error
- ;
- ;---------------------------------------------------------------
- cdrom_drive_status proc near
-
- mov dx,bx
-
- mov ah,DRVSTS_CMD ;get current drive status
- call CDREAD
- jc status_not_ready
- test al,80h
- jnz status_not_ready
- test al,(20h or 40h) ;no error, but disc changed?
- jz @f ; no
- mov cs:disc_changed[bx],1 ; yes, set the disc changed flag
- cmp dl,cs:toc_drive ;drive changed?
- jne @f ; no
- mov cs:toc_drive,0ffh ; yes
- @@:
- or al,1 ;clear zero flag
- clc ;clear carry flag
- ret
-
- status_not_ready:
- cmp dl,cs:toc_drive ;drive changed
- jne @f
- mov cs:toc_drive,0ffh
- @@:
- cmp al,10h ;if was time out error set zero flag
- stc ;set carry flag
- ret
-
- cdrom_drive_status endp
-
-
- ;---------------------------------------------------------------
- ;
- ; cdrom_audio_check
- ;
- ; Report whether the drive thinks it's in audio play mode.
- ;
- ; Entry:
- ; bx - drive number (0 based)
- ;
- ; Exit:
- ; carry set - in audio play mode
- ; carry clear - not in audio play mode
- ;
- ;---------------------------------------------------------------
- cdrom_audio_check proc near
-
- call cdrom_drive_status
- jc @f ;error occurred?
- and al,1Ch ; no, does the drive think..
- cmp al,04h ; ..it is playing audio?
- jne @f ; nope
- stc ; yep
- ret
- @@: clc
- ret
-
- cdrom_audio_check endp
-
-
- ;***************************************************************
- ;
- ; Various private helper functions.
- ;
- ;***************************************************************
-
- ;---------------------------------------------------------------
- ;
- ; status_mode_check
- ;
- ; Ancillary routine to check_device_status(). Further isolates the
- ; drive status bits to return carry clear when the drive is in a
- ; valid state.
- ;
- ;---------------------------------------------------------------
- status_mode_check proc near
-
- and al,1Ch ;mask not 'MODE' bits
- cmp al,08h ;stop/read/play/pause valid mode?
- jbe @f ; yes
- stc ; no
- ret
- @@:
- clc
- ret
-
- status_mode_check endp
-
-
- ifdef DEBUG
- ;----------------------------------------------------------------------
- ;
- ; Various routines to remain resident in driver when debugging.
- ;
- ;----------------------------------------------------------------------
-
-
-
-
-
-
- failure db '$failed',0
- media_chgd db '$media_changed',0
-
- ;----------------------------------------------------------------------
- ;
- ; disp_char_resident
- ;
- ; Displays the passed character on the console
- ;
- ; Entry:
- ; al - hex character to display.
- ;
- ;----------------------------------------------------------------------
- disp_char_resident proc near
-
- push bx ;(1) ;Save (BX)
- push cx ;(2) ;Save (CX)
- push dx ;(3) ;Save (DX)
-
- mov ah,9 ;write char
- mov bx,70h ;Reverse video
- mov cx,1
- int 10h ;IBM PC/BIOS video int. call
-
- mov ah,3 ;read cursor pos.
- mov bh,0
- int 10h
- inc dl ;Bump column by 1
- cmp dl,80 ;Past end-of-line ??
- jc same_line ; no
- ; yes
- mov dl,0 ;Cursor to start of line
- inc dh
- cmp dh,25 ;Past end-of-screen ??
- jc same_line ; no
- ; yes
- mov dh,24 ;Move back to the last line
- push dx ;(4) ;Save (cursor pos.)
- mov ax,0601h ;Scroll up one line
- mov cx,0000h ;ULcorner of screen
- mov dx,184fh ;LRcorner of screen
- int 10h
- pop dx ;(3) ;Restore (cursor pos.)
- same_line:
- mov ah,2 ;set cursor pos.
- int 10h
-
- pop dx ;(2) ;Restore (DX)
- pop cx ;(1) ;Restore (CX)
- pop bx ;(0) ;Restore (BX)
- ret
-
- disp_char_resident endp
-
-
- ;----------------------------------------------------------------------
- ;
- ; disp_msg
- ;
- ;----------------------------------------------------------------------
- public disp_msg
- disp_msg proc near
-
- next_char:
- mov al,cs:[si] ;(AL) = *(SI)++
- inc si
- and al,al ;End-of-message ??
- je exit_disp_msg ; yes
- ; no
- call disp_char_resident ;Display the character
- jmp short next_char
- exit_disp_msg:
- ret
-
- disp_msg endp
-
-
- ;----------------------------------------------------------------------
- ;
- ; disp_hex_nibble
- ;
- ;----------------------------------------------------------------------
- disp_hex_nibble proc near
-
- add al,'0' ;Add-in the "numeric" ASCII bias
- cmp al,'9' + 1 ;Greater than 9 ??
- jc lt9 ; no
- ; yes
- add al,'a' - ('9' + 1) ;Convert to "alphabetic" ASCII
- lt9:
- call disp_char_resident ;Display char. in (AL)
- ret
-
- disp_hex_nibble endp
-
-
- ;----------------------------------------------------------------------
- ;
- ; disp_hex_byte
- ;
- ;----------------------------------------------------------------------
- public disp_hex_byte
-
- disp_hex_byte proc near
-
- push ax ;(1) ;save (AX)
- push ax ;(2) ;save (lshexdigit of byte)
- shr al,1
- shr al,1
- shr al,1
- shr al,1 ;(AL) = mshexdigit
- call disp_hex_nibble ;Display hex nibble in (AL)
-
- pop ax ;(1) ;restore (lshexdigit of byte)
- and al,0fh ;(AL) = lshexdigit
- call disp_hex_nibble ;Display hex nible in (AL)
-
- pop ax ;(0) ;restore (AX)
- ret
-
- disp_hex_byte endp
-
-
- endif ;DEBUG
-
-
- _TEXT ends
-
-
-
- _LAST segment para public 'last'
- assume cs:_LAST
-
-
- ifdef DEBUG
-
- ;----------------------------------------------------------------------
- ; disp_char_inittime
- ;
- ; Output a character to the console for debugging purposes.
- ;
- ; Entry:
- ; al contains character to output.
- ;
- ;----------------------------------------------------------------------
-
- disp_char_inittime proc near
-
- push bx ;(1) ;Save (BX)
- push cx ;(2) ;Save (CX)
- push dx ;(3) ;Save (DX)
-
- mov ah,9 ;write char
- mov bx,70h ;Reverse video
- mov cx,1
- int 10h ;IBM PC/BIOS video int. call
-
- mov ah,3 ;read cursor pos.
- mov bh,0
- int 10h
- inc dl ;Bump column by 1
- cmp dl,80 ;Past end-of-line ??
- jc same_line_s ; no
- ; yes
- mov dl,0 ;Cursor to start of line
- inc dh
- cmp dh,25 ;Past end-of-screen ??
- jc same_line_s ; no
- ; yes
- mov dh,24 ;Move back to the last line
- push dx ;(4) ;Save (cursor pos.)
- mov ax,0601h ;Scroll up one line
- mov cx,0000h ;ULcorner of screen
- mov dx,184fh ;LRcorner of screen
- int 10h
- pop dx ;(3) ;Restore (cursor pos.)
- same_line_s:
- mov ah,2 ;set cursor pos.
- int 10h
-
- pop dx ;(2) ;Restore (DX)
- pop cx ;(1) ;Restore (CX)
- pop bx ;(0) ;Restore (BX)
- ret
-
- disp_char_inittime endp
-
- endif ;DEBUG
-
- ;
- ; init data variables
- ;
-
- msg db 0dh,0ah,0dh,0ah
- ifdef DEBUG
- db '*** Hitachi CD-ROM device driver, DEBUG version 2.2 ***'
- else
- db '*** Hitachi CD-ROM device driver, version 2.2 ***'
- endif
- db 0dh,0ah,' (C)Copyright Hitachi, LTD. 1987-1990.'
- db 0dh,0ah,' Device Name : ',0
- msg2 db ' ',0
- msg3 db 0dh,0ah,' Number of drives : ',0
- msg4 db 0dh,0ah,0dh,0ah,0
- errmsg1 db 0dh,0ah,' Invalid /p switch : ',0
- errmsg2 db 0dh,0ah,' Drive not ready, aborting installation',0dh,0ah,0
-
- devname_len dw 8
- devname_bufr db '12345678'
-
- CHK_IF_WORK DB ?
- TIMER_MICRO DW 0
- TIMER_MILLI DW 0
- TIMER_CONVERT DW 8381 ;838.095 ns/tick
- COUNT_CONVERT DW 54925 ;54.925 ms/count
- TEN_THOUSAND DW 10000
- THOUSAND DW 1000
- OK_COUNT DB 0
-
-
- ;============================================================
- ;
- ; INIT command
- ;
- ; This is the initialization requested from DOS in loading the device driver
- ; from the CONFIG.SYS file.
- ;
- ; Entry:
- ; ds:bx - far ptr to the request header
- ; InitHeader struc
- ;
- ; init_rqh db size Request_Hdr dup (?)
- ; init_units db ?
- ; init_endaddr dd ?
- ; init_bpbarr dd ?
- ; init_devno db ?
- ;
- ; InitHeader ends
- ;
- ;============================================================
- cdrom_init proc near
-
- ;
- ; Simple minded command line scanner
- ;
- push es
- push ds
-
- assume es:_TEXT
- mov ax,_TEXT
-
- mov es,ax
-
- lds si,ds:init_bpbarr[bx] ;get ptr to command line
- sloop:
- lodsb ;Scan for switch on command line
- cmp al,0Dh
- je cmd_done
- cmp al,0Ah
- je cmd_done
- cmp al,'/'
- je switch
-
- jmp short sloop
- cmd_done:
- jmp nomore
- ;
- ; See what switch is being specified
- ;
- switch:
- mov al,[si]
- or al,20h ;lower case
- cmp al,'c' ; /c - set minutes for power save
- jne switch_1
- jmp sw6
- switch_1:
- cmp byte ptr [si+1],':' ;Go on if letter not followed by a ':'
- jne sloop
-
- cmp al,'d' ; /d - name of device driver
- je sw2
- cmp al,'n' ; /n - number of subunits
- je sw3
- cmp al,'p' ; /p - set I/O port address
- je sw5
- jmp short sloop
-
- ;
- ; Copy command line name into device header
- ;
- sw2:
- add si,2
- mov cx,8
- mov di,offset DeviceHeader+10
- swloop:
- lodsb ;copy to ' ', CR, or LF
- cmp al,' '
- je finish
- cmp al,0dh
- je finish
- cmp al,0ah
- je finish
- cmp al,09h ;TAB
- je finish
-
-
- stosb ;offset
- loop swloop
- finish:
- dec si ;(Backup so sloop sees terminator)
- push cx ;(10) ;save cx
- cmp cx,0
- je nopad
- mov al,' ' ;pad with blanks
- wrap_up:
- stosb ;CX has count of blanks
- loop wrap_up
- nopad:
- pop ax ;(9) ;restore ax (value WAS in cx)
- mov cx,8
- sub cx,ax ;(CX) = # of chars in device name
- cmp cx,0
- jne nopad_1
- mov cx,8
- nopad_1:
- mov cs:devname_len,cx ;Save the length of the device name
-
- jmp short sloop ;Look for more (other) switches
- sw3:
- add si,2 ;skip over the 'n:'
- lodsb ;Get the digit following /n:
-
- cmp al,'1' ;Make sure numdrives is ok (1-4)
- jc sloop ; too small, look for more switches
- cmp al,'8'+1
- jnc sloop ; too large, look for more switches
-
- sub al,'0' ;Subtract out the ASCII bias
- mov es:units,al ;Setup the number of sub-units
-
- goon:
- jmp sloop ;Look for more (other) switches
- sw5:
- add si,2 ;skip over the 'p:'
- call next_hex_digit ;Get the 1st hex digit after /p:
- jc goon ;Abort if 1st hex digit was bad!
-
- mov dl,al ;(DX) = hex. value
- mov dh,0
- sw5_nextdig:
- call next_hex_digit ;Get the 2nd hex digit after /p:
- jc sw5_sport ;Jump if last digit reached
-
- mov cl,4 ;Shift prev. hex digit up 4 bits
- shl dx,cl
- or dl,al ;Or in lshexdigit
-
- jmp short sw5_nextdig
- sw5_sport:
- cmp dx,300h ;default i/o port addres??
- jne sw5_chk ; no
- dec si ; yes
- jmp goon
- sw5_chk:
-
- IRP DUMMY,<200h,220h,240h,260h,320h,340h,360h>
- cmp dx,DUMMY ;supported i/o address??
- je sw5_sport2 ; yes
- ENDM
-
- jmp goon ;not supported i/o port address
-
- sw5_sport2:
- dec si ;(Backup so sloop sees terminator)
-
- mov cx,dx
- mov dx,0 ;should be dl=0
- mov ah,MODESET_CMD
- mov al,2 ;setup based i/o port address
- call CDREAD
- jc sw5_err
- jmp goon
- sw5_err:
- mov cx,-1
- mov di,offset errmsg1
- call outstr
- jmp goon
-
- ;
- ; set the number of minutes for the power save option (or disable it)
- ;
- sw6:
-
- ifdef DEBUG
- call disp_char_inittime
- endif
- xor dx,dx ;dl = minutes before spin down
- inc si
- cmp byte ptr cs:[si],':' ;setting number of minutes?
- je @f ; yes, get how many minutes (0-14h)
- jmp short sw6_got_pwr_save ; nope, disabling power down feature
- @@: inc si
- call next_hex_digit
- jc sw6_got_pwr_save ;1st char was not valid hex?
- mov dl,al ; nope, was OK
- call next_hex_digit
- jc sw6_got_pwr_save ;was only one hex digit?
- mov cl,4 ; nope, were two digits
- shl dl,cl
- sw6_got_pwr_save:
- mov es:pwr_save,dl
- jmp goon
-
- nomore:
- mov cx,cs:devname_len
- mov si,offset DeviceHeader+10
- mov di,offset devname_bufr
- copydev:
- mov al,es:[si]
- mov cs:[di],al
- inc si
- inc di
- loop copydev
-
- mov cx,-1 ;(CX) = -1 (nul-terminated string)
- mov di,offset msg
- call outstr
-
- mov cx,cs:devname_len
- mov di,offset devname_bufr
- call outstr
-
- mov dl,es:units ;Setup the number of sub-units
- dec dl
-
- ifdef DEBUG
- push ax
- mov al,dl
- add al,'0'
- call disp_char_inittime
- pop ax
- endif
-
- cmp dl,4
- jb drive_ok
- mov ah,13h ;bad command
- call CDREAD
- jnc drive_ok
-
- ifdef DEBUG
- push ax
- mov al,ah
- add al,'0'
- call disp_char_inittime
- pop ax
- endif
-
- cmp ah,02h ;bad parameter
- jne drive_ok
- mov es:units,1 ;bad parameter
- ;support only 4 units
- drive_ok:
- mov al,es:pwr_save
-
- ifdef DEBUG
- add al,'0'
- call disp_char_inittime
- mov al,es:pwr_save
- endif
-
- mov cl,es:units
- xor ch,ch
- pwr_loop:
- push cx
- push ax
- mov ah,SET_POWER_SAVE
- mov dl,cl
- dec dl
- call CDREAD
- pop ax
- pop cx
- loop pwr_loop
- ;
- ; Initialize timing variables
- ; if successful fill in the driver's end address
- ; else fail the init
- ;
- push bx
- call init_timer_variables ;returns carry clear if successful
- pop bx ;restore request header offset
- pop ds
- mov ax,offset _LAST:very_end
- mov dx,seg _LAST
- jnc @f ;error in init?
- mov cx,-1 ; yes, print error message...
- mov di,offset errmsg2
- call outstr
- xor ax,ax ;...return 0 offset...
- mov dx,seg _TEXT ;...from DeviceHeader's segment
- and es:DeviceHeader+2,7fffh ;...and look like a block device
- stc ;skip msg3
- @@:
- mov word ptr ds:init_endaddr[bx].lo,ax
- mov word ptr ds:init_endaddr[bx].hi,dx
- mov byte ptr ds:init_units[bx],0
- mov byte ptr ds:init_devno[bx],0
- jc @f ;skip msg3?
-
- mov cx,-1 ; no, must have init'd OK
- mov di,offset msg3
- call outstr
- mov dl,es:units
- add dl,'0'
- mov ah,02h
- int 21h
- @@:
- mov cx,-1
- mov di,offset msg4
- call outstr
-
- assume es:nothing
- pop es
- ret
-
- cdrom_init endp
-
-
- ;----------------------------------------------------------------------
- ; outstr
- ;
- ; Output a string to stdout
- ;
- ; Entry:
- ; cs:di - points to string
- ; cx - contains string length (if not null terminated)
- ;
- ; Exit
- ;----------------------------------------------------------------------
- outstr proc near
-
- push ax ;(1) ;save (AX)
- push dx ;(2) ;save (DX)
- oloop:
- mov dl,cs:[di]
- inc di
-
- and dl,dl ;Reached null termination ??
- jz done ; yes
- ; no
- mov ah,02h ;write char to STO
- int 21h
-
- loop oloop ;Loop until (CX) = 0 or null
- done:
- pop dx ;(1) ;restore (DX)
- pop ax ;(0) ;restore (AX)
-
- ret
-
- outstr endp
-
-
- ;----------------------------------------------------------------------
- ;
- ; next_hex_digit
- ;
- ; Return the next hex digit on the command line
- ;
- ;----------------------------------------------------------------------
- next_hex_digit proc near
-
- lodsb ;Get the next byte from cmd line
- cmp al,'0' ;Numeric digit ??
- jc not_hdig ; no
- ; maybe
- cmp al,'9'+1 ;Numeric digit ??
- jc is_numdig ; yes
- ; no
- cmp al,'A' ;(A-F) digit ??
- jc not_hdig ; no
- ; maybe
- cmp al,'F'+1 ;(A-F) digit ??
- jc is_uafdig ; yes
- ; no
- cmp al,'a' ;(a-f) digit ??
- jc not_hdig ; no
- ; maybe
- cmp al,'f'+1 ;(a-f) digit ??
- jnc not_hdig ; no
- ; yes
- sub al,('a'-10) ;Convert to hex. value
- is_hdig:
- clc ;Clear carry & return
- ret ;(hex. value in AL)
- is_uafdig:
- sub al,('A'-10) ;Convert to hex. value
- jmp short is_hdig
- is_numdig:
- sub al,'0' ;Conver to hex. value
- jmp short is_hdig
- not_hdig:
- stc ;Set carry & return
- ret ;(ASCII char. in AL)
-
- next_hex_digit endp
-
-
- ;---------------------------------------------
- ;
- ; Timer variable initialization
- ;
- ; This was located in CDREAD() and done on the first READ call,
- ; now it's done when the driver is installed.
- ;
- ; (You don't want to look at this stuff if you don't have to!!!)
- ;
- ; Entry:
- ; es - _TEXT
- ;
- ; Register usage:
- ; cs - _LAST (use cs override for _LAST variables)
- ; ds - _TEXT
- ; es - _TEXT
- ;
- ; Exit:
- ; carry clear - successful init
- ; carry set - drive not ready error (probably turned off)
- ;
- ;---------------------------------------------
- init_timer_variables proc near
-
- mov ax,_TEXT
- mov ds,ax
-
- MOV BP,WORD PTR CURRENT_IF
- INC BP ;POINT AT PPI_PB
-
- CALL CPU_CHK ;CHECK CPU type
- CALL CHK_IF ;returns zero set if error
- jnz @f
- stc ;carry set for init error
- ret
- @@:
- CMP CPU_MODE,2
- JNZ @f
- CALL CLOCK_CALC ;80286
- JNC done_timer_init
- CALL CLOCK_CALC
- JMP SHORT done_timer_init
- @@: ;8088
- CALL CLOCK_CALC_88
- JNC done_timer_init
- CALL CLOCK_CALC_88
- done_timer_init:
- clc ;carry clear for successful init
- ret
-
- init_timer_variables endp
-
-
-
- CPU_CHK PROC NEAR
- XOR BL,BL
- MOV AX,4
- MOV CL,20H
- SHR AX,CL
- TEST AX,4
- JZ CPU_CHK_END
- PUSH SP
- POP AX
- CMP AX,SP
- JNZ CPU_CHK_END
- MOV BL,2 ;80286 MODE
- CPU_CHK_END:
- MOV CPU_MODE,BL
- RET
- CPU_CHK ENDP
-
-
-
- CHK_IF PROC NEAR ; CHECK IF CARD
- CHK_IF_LOOP_1:
- MOV TWICE,2
- CHK_IF_LOOP_2:
- MOV ERRCNT,RETRY2
- MOV CS:CHK_IF_WORK,AH
- DEC TWICE
- CHK_IF_1:
- MOV IF_FLAG,1
- CALL _STATUS_COMMAND ;ISSUE STATUS COMMAND
- MOV IF_FLAG,0
- JNZ CHK_IF_0
- DEC ERRCNT ;RETRY
- JNZ CHK_IF_1
- RET
- CHK_IF_0:
- XOR AH,AH
- MOV AL,BYTE PTR STA_CODE ;SET STATUS CODE IN AL
- CMP AL,0FFH
- JNE CHK_IF_TWICE ;SUPPORT SOFT TRNS
- INC AH ;NOT SUPPRORT SOFT TRNS
- CHK_IF_TWICE:
- CMP TWICE,0
- JNE CHK_IF_LOOP_2 ;2nd CHECK
- CHK_IF_2:
- CMP AH,CS:CHK_IF_WORK
- JNE CHK_IF_LOOP_1 ;TRY AGAIN
- CHK_IF_3:
- MOV BYTE PTR CURRENT_IF_MODE,AH
- OR AH,80H
- RET
- CHK_IF ENDP
-
-
- CLOCK_CALC PROC NEAR
- XOR AL,AL
- MOV CLOCK_COUNT,AL
- CALL INSB_INIT
- TIMER_LOOP_0:
- MOV CS:OK_COUNT,2
- TIMER_LOOP_1:
- MOV CX,1000
- LEA DI,_TEXT:BUF
- CALL TIMER_START
- CALL _INSB_LOOP_ENT ; far entry point
- CALL TIMER_STOP
- ;
- CALL TIMER_CHK
- JZ LOW_CLOCK ;TOO LOW CLOCK
- JB NEXT_LOOP ; YET HIGH
- DEC CS:OK_COUNT
- JNZ TIMER_LOOP_1
- OK_END:
- MOV CLOCK_MODE,0
- CALL TIMER_RESTORE
- CLC
- RET
-
- INSB_INIT proc near
- LEA DI,_TEXT:INSB_LOOP
- MOV AX,0E26CH ;INSB ,LOOP
- STOSW ;es -> _TEXT
- MOV AX,0C3FDH ;RET
- STOSW
- RET
- INSB_INIT endp
-
-
- HIGH_CLOCK:
- LOW_CLOCK:
- BAD_END:
- MOV CLOCK_MODE,80H
- CALL TIMER_RESTORE
- STC
- RET
- ;
- NEXT_LOOP:
- INC CLOCK_COUNT
- CMP CLOCK_COUNT,100
- JNB HIGH_CLOCK ;TOO HIGH CLOCK
- ;
- SUB_1:
- MOV CL,CLOCK_COUNT
- XOR CH,CH
- LEA DI,_TEXT:INSB_LOOP
- INC DI
- MOV AL,90H ;NOP
- REP STOSB
- MOV AL,0E2H ;LOOP
- STOSB
- MOV AL,0FDH
- SUB AL,CLOCK_COUNT
- STOSB
- MOV AL,0C3H ;----- added 4/2
- STOSB ;----- added 4/2
- JMP TIMER_LOOP_0
- ;
- TIMER_CHK:
- CMP CS:TIMER_MILLI,5
- JAE LOW_NEXT ;TOO SLOW
- CMP CS:TIMER_MILLI,3
- JA CHK_NEXT
- JB HIGH_NEXT
- CMP CS:TIMER_MICRO,700
- JBE HIGH_NEXT
- CHK_OK:
- OR AX,1
- CLC
- RET
- HIGH_NEXT:
- OR AL,1
- STC
- RET
- CHK_NEXT:
- CMP CS:TIMER_MICRO,999
- JB CHK_OK
- LOW_NEXT:
- XOR AL,AL
- RET
- ;
- TIMER_RESTORE:
- CLI
- PUSH AX
- MOV AL,00110110B ;CNT 0,LSB then MSB, MODE 2, BINARY
- OUT TIMER_MODE,AL
- JMP SHORT $+2
- SUB AX,AX
- OUT TIMER0,AL
- JMP SHORT $+2
- OUT TIMER0,AL
- POP AX
- STI
- RET
- ;
- CLOCK_CALC ENDP
- ;------------------------------------------------------------------
- CLOCK_CALC_88 PROC NEAR
- MOV AX,CS
- MOV ES,AX
- XOR AL,AL
- MOV CLOCK_COUNT,AL
- CALL INSB_INIT_88
- CALC_88_LOOP_0:
- MOV CS:OK_COUNT,2
- CALC_88_LOOP_1:
- MOV CX,31
- CMP CLOCK_COUNT,1
- JBE CALC_88_LOOP_3
- MOV CX,62
- CMP CLOCK_COUNT,3
- JBE CALC_88_LOOP_3
- MOV CX,1000
- CALC_88_LOOP_3:
- LEA DI,_TEXT:BUF
- CALL TIMER_START
- CALL _INSB_LOOP_ENT ;far entry point
- CALL TIMER_STOP
-
- CALL TIMER_CHK
- JZ LOW_CLOCK_88 ;TOO LOW CLOCK
- JB NEXT_LOOP_88 ; YET HIGH
- DEC CS:OK_COUNT
- JNZ CALC_88_LOOP_1
- OK_END_88:
- MOV CLOCK_MODE,0
- CALL TIMER_RESTORE
- CLC
- RET
-
- HIGH_CLOCK_88:
- LOW_CLOCK_88:
- BAD_END_88:
- MOV CLOCK_MODE,80H
- CALL TIMER_RESTORE
- STC
- RET
- ;
- NEXT_LOOP_88:
- MOV CX,32
- INC CLOCK_COUNT
- CMP CLOCK_COUNT,1
- JE NOP_1
- SHR CX,1 ;16
- CMP CLOCK_COUNT,3
- JBE NOP_23
- CMP CLOCK_COUNT,100
- JNB HIGH_CLOCK_88 ;TOO HIGH CLOCK
- ;
- SUB_1_88:
- MOV CL,CLOCK_COUNT
- SUB CL,4
- XOR CH,CH
- LEA DI,_TEXT:INSB_LOOP
- INC DI
- INC DI
- CMP CX,0
- JE SUB_1_88_1
- MOV AL,90H ;NOP
- REP STOSB
- SUB_1_88_1:
- MOV AL,0E2H ;LOOP
- STOSB
- MOV AL,00H
- SUB AL,CLOCK_COUNT
- STOSB
- MOV AL,0C3H
- STOSB
- JMP CALC_88_LOOP_0
- NOP_1:
- LEA DI,INSB_LOOP
- MOV AX,0AAECH ;IN AL,DX STOSB
- MOV BL,90H ;NOP
- NOP_1_1:
- STOSW
- XCHG AL,BL
- STOSB
- XCHG AL,BL
- LOOP NOP_1_1
- MOV AL,0E2H
- STOSB
- MOV AL,09EH
- STOSB
- MOV AL,0C3H
- STOSB
- JMP CALC_88_LOOP_0
- NOP_23:
- MOV AX,0AAECH ;IN AL,DX STOSB
- MOV BX,9090H ;NOP NOP
- LEA DI,_TEXT:INSB_LOOP
- NOP_23_1:
- STOSW
- XCHG AX,BX
- STOSW
- CMP CLOCK_COUNT,2
- JE NOP_23_2
- STOSB
- NOP_23_2:
- XCHG AX,BX
- LOOP NOP_23_1
- MOV AL,0E2H
- STOSB
- MOV AL,0BEH
- CMP CLOCK_COUNT,2
- JE NOP_23_3
- SUB AL,10H
- NOP_23_3:
- STOSB
- MOV AL,0C3H
- STOSB
- JMP CALC_88_LOOP_0
- ;
- INSB_INIT_88:
- LEA DI,_TEXT:INSB_LOOP
- MOV CX,32
- MOV AX,0AAECH ;IN AL,DX STOSB
- REP STOSW
- MOV AX,0BEE2H ;LOOP
- STOSW
- MOV AL,0C3H ;RET
- STOSB
- RET
- ;
-
- CLOCK_CALC_88 ENDP
-
-
- ; *** TIMER START ROUTINE
-
- TIMER_START PROC NEAR ;internal timing resolution = 838 ns
- CLI
- MOV CS:TIMER_MICRO,0
- MOV CS:TIMER_MILLI,0
- ;--- INITIALIZE COUNTER 0 OF 8253 TIMER ----
- MOV AL,00110100B ;CNT 0,LSB then MSB, MODE 2, BINARY
- OUT TIMER_MODE,AL
- JMP SHORT $+2
- SUB AX,AX
- OUT TIMER0,AL
- JMP SHORT $+2
- OUT TIMER0,AL
- RET
- TIMER_START ENDP
-
- ; *** TIMER_STOP ROUTINE ***
-
- TIMER_STOP PROC NEAR
- MOV AL,00H
- OUT TIMER_MODE,AL ;LATCH COUNTER ( 16 bits )
- JMP SHORT $+2
- IN AL,TIMER0 ;READ LOWER 8 bits
- JMP SHORT $+2
- MOV DL,AL
- IN AL,TIMER0 ;READ HIGHER 8 bits
- MOV DH,AL ;DX HAS 16 BIT TIMER COUNT
- STI
- ;-- CALC THE TIME
- XOR AX,AX
- SUB AX,DX
- MUL CS:TIMER_CONVERT
- DIV CS:TEN_THOUSAND
- MOV CS:TIMER_MICRO,AX
- MOV AX,CS:TIMER_MICRO
- CMP AX,1000
- JB FLD_OK
- SUB DX,DX
- DIV CS:THOUSAND
- MOV CS:TIMER_MILLI,AX
- MOV CS:TIMER_MICRO,DX
- FLD_OK:
- DISP_END:
- RET
- TIMER_STOP ENDP
-
- _LAST ends
-
- end
-
-